package com.ruoyi.common.utils.tool;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Base64;
import java.util.Iterator;

public class ImgUtils {

    /**
     * 生成本地图片
     *
     * @param photo
     * @param saveName
     * @return
     */
    public static boolean generateLocalImage(String photo, String saveName) {
        return photo.startsWith("http") ? netToLocalImage(photo, saveName) : base64ToLocalImage(photo, saveName);
    }

    /**
     * 网络图片保存本地
     *
     * @param imageUrl
     * @param saveName
     * @throws Exception
     */
    public static boolean netToLocalImage(String imageUrl, String saveName) {
        InputStream is = null;
        OutputStream os = null;
        try {
            URL url = new URL(imageUrl);
            is = url.openStream();
            byte[] buffer = new byte[1024];
            File file = new File(saveName);
            // 判断文件是否存在,存在直接返回
            if (file.exists()) return true;
            os = new FileOutputStream(file);
            if (!file.exists()) file.mkdirs();
            int len;
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            return true;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) is.close();
                if (os != null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 网络图片转换Base64
     *
     * @param netImagePath
     */
    public static String netImageToBase64(String netImagePath) {
        HttpURLConnection conn = null;
        InputStream is = null;
        try {
            // 创建URL
            URL url = new URL(netImagePath);
            final byte[] by = new byte[1024];
            // 创建链接
            conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            final ByteArrayOutputStream data = new ByteArrayOutputStream();
            is = conn.getInputStream();
            // 将内容读取内存中
            int len = -1;
            while ((len = is.read(by)) != -1) {
                data.write(by, 0, len);
            }
            // 对字节数组Base64编码
            //BASE64Encoder encoder = new BASE64Encoder();
            //return encoder.encode(data.toByteArray());
            return Base64.getEncoder().encodeToString(data.toByteArray());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) is.close();
                if (conn != null) conn.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 本地图片转换Base64
     *
     * @param imgPath 待处理图片
     * @return
     */
    public static String localImageToBase64(String imgPath) {
        InputStream is = null;
        try {
            // 将图片文件转化为字节数组字符串，并对其进行Base64编码处理
            is = new FileInputStream(imgPath);
            // 读取图片字节数组
            byte[] data = new byte[is.available()];
            is.read(data);
            return Base64.getEncoder().encodeToString(data);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 对字节数组字符串进行Base64解码并生成图片
     *
     * @param photo       图片数据
     * @param imgFilePath 保存图片全路径地址
     * @return
     */
    public static boolean base64ToLocalImage(String photo, String imgFilePath) {
        if (photo == null) return false;
        OutputStream os = null;
        try {
            // Base64解码
            //BASE64Decoder decoder = new BASE64Decoder();
            //byte[] b = decoder.decodeBuffer(base64DelHeader(photo));
            byte[] b = Base64.getDecoder().decode(base64DelHeader(photo));
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }
            // 生成jpg图片
            os = new FileOutputStream(imgFilePath);
            os.write(b);
            os.flush();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 去掉图片的base64的头部
     *
     * @param photo
     * @return
     * @throws Exception
     */
    public static String base64DelHeader(String photo) {
        return photo.substring(photo.indexOf(",") + 1);
    }

    /**
     * 图片裁剪
     *
     * @param srcPath
     * @param subPath
     * @param x
     * @param y
     * @param width
     * @param height
     * @return
     * @throws FileNotFoundException
     */
    public static String cut(String srcPath, String subPath, int x, int y, int width, int height) {
        FileInputStream fis = null;
        ImageInputStream iis = null;
        try {
            // 读取图片文件
            fis = new FileInputStream(srcPath);
            String suffix = srcPath.substring(srcPath.lastIndexOf(".") + 1);
            // 返回包含所有当前已注册 ImageReader 的 Iterator，这些 ImageReader 声称能够解码指定格式。
            // 参数：formatName - 包含非正式格式名称 .（例如 "jpeg" 或 "tiff"）等 。
            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(suffix);
            ImageReader reader = it.next();
            // 获取图片流 ImageIO.createImageInputStream(fis);
            iis = ImageIO.createImageInputStream(fis);
            // iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
            // 此设置意味着包含在输入源中的图像将只按顺序读取，可能允许 reader避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
            reader.setInput(iis, true);
            // 描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O 框架的上下文中的流转换一幅图像或一组图像。
            // 用于特定图像格式的插件 将从其 ImageReader 实现的 getDefaultReadParam 方法中返回
            // ImageReadParam 的实例。
            ImageReadParam param = reader.getDefaultReadParam();
            // 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域，通过 Rectangle
            // 对象的左上顶点的坐标（x，y）、宽度和高度可以定义这个区域。
            Rectangle rect = new Rectangle(x, y, width, height);
            // 提供一个 BufferedImage，将其用作解码像素数据的目标。
            param.setSourceRegion(rect);
            // 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象，并将
            // 它作为一个完整的BufferedImage 返回。
            BufferedImage bi = reader.read(0, param);
            // 保存新图片
            ImageIO.write(bi, "JPEG", new File(subPath));
            return subPath;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null) fis.close();
                if (iis != null) iis.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    /**
     * 对图片进行放大
     *
     * @param originalImage 原始图片
     * @param times         放大倍数
     * @return
     */
    public static BufferedImage zoomInImage(BufferedImage originalImage, int times) {
        int width = originalImage.getWidth() * times;
        int height = originalImage.getHeight() * times;
        BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());
        Graphics g = newImage.getGraphics();
        g.drawImage(originalImage, 0, 0, width, height, null);
        g.dispose();
        return newImage;
    }

    /**
     * 对图片进行放大
     *
     * @param srcPath 原始图片路径(绝对路径)
     * @param newPath 放大后图片路径（绝对路径）
     * @param times   放大倍数
     * @return 是否放大成功
     */
    public static boolean zoomInImage(String srcPath, String newPath, int times) {
        try {
            File of = new File(srcPath);
            if (of.canRead()) {
                BufferedImage bufferedImage = ImageIO.read(of);
                bufferedImage = zoomInImage(bufferedImage, times);
                ImageIO.write(bufferedImage, "JPG", new File(newPath));
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 对图片进行缩小
     *
     * @param originalImage 原始图片
     * @param times         缩小倍数
     * @return 缩小后的Image
     */
    public static BufferedImage zoomOutImage(BufferedImage originalImage, int times) {
        int width = originalImage.getWidth() / times;
        int height = originalImage.getHeight() / times;
        BufferedImage newImage = new BufferedImage(width, height, originalImage.getType());
        Graphics g = newImage.getGraphics();
        g.drawImage(originalImage, 0, 0, width, height, null);
        g.dispose();
        return newImage;
    }

    /**
     * 对图片进行缩小
     *
     * @param srcPath 源图片路径（绝对路径）
     * @param newPath 新图片路径（绝对路径）
     * @param times   缩小倍数
     * @return 保存是否成功
     */
    public static boolean zoomOutImage(String srcPath, String newPath, int times) {
        try {
            File of = new File(srcPath);
            if (of.canRead()) {
                BufferedImage bufferedImage = ImageIO.read(of);
                bufferedImage = zoomOutImage(bufferedImage, times);
                ImageIO.write(bufferedImage, "JPG", new File(newPath));
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 判断图片是否存在本地，存在则返回，不存在则下载
     * @param imageUrl
     * @return
     */
    public static String downloadIfNotExists(String imageUrl)
    {
        try {
            // 从URL中获取图片文件名（简单的处理，可能需要根据实际情况优化）
            String mLocalPhotoPath = "D:\\wwwroot\\wisdom\\java\\wisdom-local-service\\static\\pic\\download\\";
            // 创建目录
            File directory = new File(mLocalPhotoPath);
            if (!directory.exists()) {
                if (directory.mkdirs()) {
                    System.out.println("目录 " + mLocalPhotoPath + " 创建成功");
                } else {
                    System.out.println("目录 " + mLocalPhotoPath + " 创建失败");
                }
            }
            // 下载文件
            String fileName = imageUrl.substring(imageUrl.lastIndexOf('/') + 1);
            File localFile = new File(mLocalPhotoPath + fileName);
            if (!localFile.exists()) {
                URL url = new URL(imageUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestMethod("GET");

                // 获取网络图片的输入流
                InputStream inputStream = connection.getInputStream();
                // 创建本地文件的输出流
                FileOutputStream outputStream = new FileOutputStream(localFile);

                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer))!= -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }

                outputStream.close();
                inputStream.close();
                connection.disconnect();
                System.out.println("图片已下载到本地: " + localFile.getAbsolutePath());
                return localFile.getAbsolutePath();
            } else {
                System.out.println("图片已存在本地，无需下载: " + localFile.getAbsolutePath());
                return localFile.getAbsolutePath();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}